﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
using System.Text;
using MySQL.Db;
using Gollie.WebCache;
using Gollie.Extensions;
using Gollie.Invoice;
using Gollie.Database;
using Gollie.Mail;
using NLog;

namespace Gollie.DataTables
{
	public class PaymentsToVendorDataItem
	{
		public uint VendorId { get; set; }
		public string Billingname { get; set; }
		public string Billingcity { get; set; }
		public string Billingcountry { get; set; }
		public string Billingaccount { get; set; }
		public string Billingemail { get; set; }
		public decimal Deposits { get; set; }
		public decimal ToPay { get; set; }
		public decimal Alreadypaid { get; set; }
		public decimal Lefttopay { get; set; }
		public decimal Grossfee { get; set; }
		public decimal Totalvat { get; set; }
		public decimal Correctionfee { get; set; }
		public decimal Netfee { get; set; }
		public decimal Totaldiscount { get; set; }
	}

	public class PaymentsToVendorData : BaseBindable<PaymentsToVendorDataItem>
	{
		private static Logger logger = LogManager.GetCurrentClassLogger();

		internal decimal totalDeposits = 0;
		internal decimal totalDebt = 0;
		internal decimal totalPaid = 0;
		internal decimal totalDebtLeft = 0;
		internal decimal totalDiscount = 0;
		internal decimal grossFee = 0;
		internal decimal netFee = 0;
		internal decimal totalVat = 0;

		private int month;
		private int year;

		public PaymentsToVendorData(int month, int year)
		{
			this.month = month;
			this.year = year;

			this.GetInvoiceData(month, year);
		}

		private void GetInvoiceData(int month, int year)
		{
			InvoiceCalculatorCollection invoiceCalculators = new InvoiceCalculatorCollection(month, year);

			foreach (KeyValuePair<uint, InvoiceCalculator> kvp in invoiceCalculators)
			{
				this.FinalizeVendor(kvp.Key, kvp.Value, month, year);
			}
		}

		private void FinalizeVendor(uint vendorId, InvoiceCalculator invoiceCalculator, int month, int year)
		{
			//gives just one row!
			ResultSet resultSetPayments = Database.Queries.GetPaymentsToVendor(vendorId, month, year);

			decimal alreadyPayed = resultSetPayments.GetDecimal(0, "alreadypayed");

			decimal totalDebtToVendor = invoiceCalculator.TotalDeposit - invoiceCalculator.NetFee - invoiceCalculator.TotalVat;
			decimal currentDebtToVendor = totalDebtToVendor - alreadyPayed;

			this.totalDeposits += invoiceCalculator.TotalDeposit;
			this.grossFee = invoiceCalculator.GrossFee;
			this.totalDiscount = invoiceCalculator.TotalDiscount;
			this.netFee += invoiceCalculator.NetFee;
			this.totalVat += invoiceCalculator.TotalVat;
			this.totalDebt += totalDebtToVendor;
			this.totalPaid += alreadyPayed;
			this.totalDebtLeft += currentDebtToVendor;

			this.Add(new PaymentsToVendorDataItem()
			{
				VendorId = vendorId,
				Billingname = resultSetPayments.GetString(0, "billingname"),
				Billingcity = resultSetPayments.GetString(0, "billingcity"),
				Billingcountry = resultSetPayments.GetString(0, "billingcountry"),
				Billingaccount = resultSetPayments.GetString(0, "billingaccount"),
				Billingemail = resultSetPayments.GetString(0, "billingemail"),
				Deposits = invoiceCalculator.TotalDeposit,
				Alreadypaid = alreadyPayed,
				Grossfee = invoiceCalculator.GrossFee,
				ToPay = totalDebtToVendor,
				Lefttopay = currentDebtToVendor,
				Totalvat = invoiceCalculator.TotalVat,
				Correctionfee = invoiceCalculator.CorrectionFeeBelowMinimum,
				Netfee = invoiceCalculator.NetFee,
				Totaldiscount = -invoiceCalculator.TotalDiscount
			});
		}

		internal void RegisterAllPayments()
		{
			QueryCollection paymentQueries = new QueryCollection();
			EMailCollection emails = new EMailCollection();

			foreach (PaymentsToVendorDataItem item in this)
			{
				if (item.Lefttopay <= 0.01M)
					continue;

				Query query;
				EMail email;

				CreateQueryAndEmail(out query, out email, item);

				paymentQueries.Add(query);
				emails.Add(email);
			}

			paymentQueries.Execute();

			MailClient.Queue(emails);
		}

		internal void RegisterPayment(uint vendorId)
		{
			PaymentsToVendorDataItem item = this.SingleOrDefault(x => x.VendorId == vendorId);

			if (item == null)
			{
				logger.Error("Could not find vendor {0} in PaymentsToVendorData", vendorId);

				return;
			}

			Query query;
			EMail email;

			CreateQueryAndEmail(out query, out email, item);

			query.Execute();
			MailClient.Queue(email);
		}

		private void CreateQueryAndEmail(out Query query, out EMail email, PaymentsToVendorDataItem item)
		{
			decimal grossFee = item.Grossfee;
			decimal correctionFee = item.Correctionfee;

			uint vendorId = item.VendorId;
			string emailAddress = item.Billingemail;
			string name = item.Billingname;
			string city = item.Billingcity;
			string bankaccount = item.Billingaccount;
			decimal deposits = item.Deposits;
			decimal staffelFee = grossFee - correctionFee;
			decimal totalFee = grossFee;
			decimal discount = item.Totaldiscount;
			decimal netFee = item.Netfee;
			decimal vat = item.Totalvat;
			decimal alreadyPaid = item.Alreadypaid;
			decimal amountToPay = item.Lefttopay;

			decimal totaldeductions = 0 - (totalFee + vat + alreadyPaid + discount);

			string period = new DateTime(year, month, 1).ToString("MMMM yyyy");

			query = Database.Queries.GetInsertPaymentToVendoryQuery(vendorId, month, year, amountToPay);

			email = new EMail
					{
						Name = "youvebeenpaid",
						Recipients = emailAddress,
						Args = new Dictionary<string, string>()
						{
													{ "{billingname}", name },
													{ "{billingcity}", city },
													{ "{billingaccount}", bankaccount },
													{ "{aanhef}", "Geachte relatie,<br/><br/>" },
													{ "{deposits}", deposits.ToString("c2") },
													{ "{staffelfee}", staffelFee.ToString("c2") },
													{ "{correctionfee}", correctionFee.ToString("c2") },
													{ "{totalfee}", netFee.ToString("c2") },
													{ "{overig}", this.GetDiscountMailPart(totalFee, discount)},
													{ "{vat}", vat.ToString("c2") },
													{ "{vatpercentage}", (InvoiceData.Instance.VatPercentage/100).ToString("p") },
													{ "{alreadypaid}", alreadyPaid.ToString("c2") },
													{ "{paidnow}", amountToPay.ToString("c2") },
													{ "{deductions}", totaldeductions.ToString("c2") },
													{ "{minimumfee}", InvoiceData.Instance.MinimumFeePerDeposit.ToString("c2") },
													{ "{period}", period }
										    
						}
					};
		}

		private string GetDiscountMailPart(decimal totalFee, decimal discount)
		{
			if (discount == 0)
				return "";

			StringBuilder str = new StringBuilder();
			str.Append("<tr><td>Korting:</td><td></td><td class=\"value\">");
			str.Append(discount.ToString("c2"));
			str.Append("</td></tr>");

			return str.ToString();
		}

		internal decimal GetAmountToPay(uint vendorId)
		{
			PaymentsToVendorDataItem item = this.SingleOrDefault(x => x.VendorId == vendorId);
			return (item != null ? item.Lefttopay : 0);
		}
	}
}